﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ZackFlame.IronBrainFuck
{
    /// <summary>
    /// Вспомогательный класс для ввода и вывода в BrainFuck программе.
    /// </summary>
    public static class IOHelper
    {
        static readonly Encoding internalEncoding = Encoding.Default;

        /// <summary>
        /// Считывает символ и возвращает его значение в системной кодировке.
        /// </summary>
        /// <param name="input">Поток для чтения.</param>
        /// <returns>Код считанного символа в кодировке Encoding.Default.</returns>
        /// <remarks>
        /// При чтении игнорируется символ '\r', читается только '\n'.
        /// </remarks>
        public static UInt16 ReadChar(TextReader input)
        {
            if (input != null)
            {
                char ch;
                do
                {
                    ch = (char)input.Read();
                }
                while (ch == '\r');

                return internalEncoding.GetBytes(new char[] { ch })[0];
            }

            return 0;
        }

        /// <summary>
        /// Считывает числовое беззнаковое значение от 0 до UInt16.MaxValue.
        /// Если считанное значение отрицательно, то вычитает его из
        /// Int16.MaxValue и возвращает результат.
        /// </summary>
        /// <param name="input">Поток для чтения.</param>
        /// <returns>Считанное значение в виде беззнакового UInt16.</returns>
        public static UInt16 ReadCell(TextReader input)
        {
            if (input != null)
            {
                string text = input.ReadLine();
                if (text.Length > 0)
                {
                    if (text.StartsWith("-"))
                    {
                        UInt16 number = UInt16.Parse(text.Substring(1));
                        return (UInt16)(UInt16.MaxValue - number + 1);
                    }
                    else
                    {
                        return (UInt16)UInt16.Parse(text);
                    }
                }
            }

            return 0;
        }

        /// <summary>
        /// Записывает символ, представленный в виде кода в системной
        /// кодировке.
        /// </summary>
        /// <remarks>
        /// Символ '\n' трактуется как перевод строки в текущей среде.
        /// </remarks>
        /// <param name="value">Код символа.</param>
        /// <param name="output">Поток для записи.</param>
        public static void WriteChar(UInt16 value, TextWriter output)
        {
            if (output == null)
                return;

            char ch = internalEncoding.GetChars(
                new byte[] { (byte)value })[0];

            output.Write(ch != '\n' ? ch.ToString() : Environment.NewLine);
        }

        /// <summary>
        /// Записывает информацию о текущей ячейке в виде 
        /// [номер=значение(символ)], где символ - это значение ячейки,
        /// представленное в виде символа в системной кодировке.
        /// </summary>
        /// <remarks>
        /// Символ с кодом 0 и символ '\n' не выводятся.
        /// </remarks>
        /// <param name="index">Номер ячейки.</param>
        /// <param name="value">Значение ячейки.</param>
        /// <param name="output">Поток для записи.</param>
        public static void WriteCell(UInt16 index, UInt16 value, TextWriter output)
        {
            if (output == null)
                return;

            char ch = internalEncoding.GetChars(
                new byte[] { (byte)value })[0];

            string str = string.Empty;
            if (ch != 0 && ch != '\n')
                str = "(" + ch.ToString() + ")";

            output.WriteLine("[{0}={1}{2}]", index, value, str);
        }
    }
}
